package org.zh.sh.util.create;

import org.zh.sh.config.ZHOpenApplication;

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static org.zh.sh.config.GlobalStatic.*;
import static org.zh.sh.util.create.TablesInfo.*;

public class JavaCreate {


    public static void main(String[] args) throws SQLException, IOException {
        env.load(ZHOpenApplication.class.getClassLoader().getResourceAsStream("ZHOpen.properties"));
        String[] split = env.getProperty(zhOpenTables).split(",");
        for (String tb:split) {
            createJavaClass(tb,getConn(SQLiteType),SQLiteType);
        }
    }

    public static void createJavaClass(String tableName, Connection conn, String dbType) throws SQLException, IOException {
        TableInfo tInfo = null;
        if (dbType.equals(mysqlType)) {
            MysqlTablesInfo info = MysqlTablesInfo.info;
            tInfo = info.columnsInfo(tableName, conn);
        }
        if (dbType.equals(SQLiteType)) {
            SQLiteTablesInfo info = SQLiteTablesInfo.info;
            tInfo= info.columnsInfo(tableName, conn);
        }
        if (tInfo != null) {
            createBean(tInfo);
            createSV(tInfo);
            createVLL(tInfo);
            createVLLTest(tInfo);
            createTestBean(tInfo);
        }

    }

    private static void createBean(TableInfo tInfo) throws IOException {
        String dir = System.getProperty("user.dir");
        Path path = Paths.get(dir, "clazz/entity", tInfo.clazzName() + ".java");
        Files.deleteIfExists(path);
        Files.createDirectories(path.getParent());
        BufferedWriter bw = Files.newBufferedWriter(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
        List<ColumnInfo> cInfos = tInfo.columns();
        String map = "\n" +
                     "public class " + tInfo.clazzName() + " {\n";
        for (ColumnInfo cInfo : cInfos) {
            map += "    /**\n" +
                   "     * description=" + cInfo.description() + "-->javaType=" + cInfo.javaType() + "-->columnType=" + cInfo.columnType() + "-->PRI=" + cInfo.PRI() + "-->autoincrement=" + cInfo.autoincrement() +
                   "     */\n" +
                   "    public static final String " + cInfo.columnName() + " = \"" + cInfo.columnName() + "\";\n";
        }
        map += "\n" +
               "    public static final String tableName = \"" + tInfo.tableName() + "\";\n" +
               "    public static final String queryById = \"select * from " + tInfo.tableName() + " where " + tInfo.clazzAlias() + "Id = ?\";\n" +
               "    public static final String deleteById = \"delete from " + tInfo.tableName() + " where " + tInfo.clazzAlias() + "Id = ?\";\n" +
               "    public static final String updateAll = \"update " + tInfo.tableName() + " set ";
        for (ColumnInfo cInfo : cInfos) {
            if (cInfo.autoincrement()) {
                if (cInfos.indexOf(cInfo) == (cInfos.size() - 1)) {
                    map += cInfo.columnName() + " = ? ";
                } else {
                    map += cInfo.columnName() + " = ? ,";
                }
            }
        }
        map += "where " + tInfo.clazzAlias() + "Id = ?\";" +
               "\n" +
               "}";
        bw.write(map);
        bw.flush();
        bw.close();
    }

    private static void createSV(TableInfo tInfo) throws IOException {
        String dir = System.getProperty("user.dir");
        Path path = Paths.get(dir, "clazz/sv", tInfo.clazzName() + "SV.java");
        Files.deleteIfExists(path);
        Files.createDirectories(path.getParent());
        BufferedWriter bw = Files.newBufferedWriter(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE);

        String service = "import org.zh.sh.util.jdbc.ZHOpenJdbcUtil;\n" +
                         "\n" +
                         "import java.sql.SQLException;\n" +
                         "import java.util.Map;\n" +
                         "import org.zh.sh.util.proxy.Service;\n" +
                         "import org.zh.sh.util.jdbc.Transaction;\n" +
                         "@Service\n" +
                         "public class " + tInfo.clazzName() + "SV extends " + tInfo.clazzName() + "{\n" +

                         "\n" +
                         "    @Transaction\n" +
                         "    public Map<String, Object> insert(Map<String, Object> " + tInfo.clazzAlias() + ")  {\n" +
                         "        return ZHOpenJdbcUtil.insertPri(tableName,removeEmpty(" + tInfo.clazzAlias() + "));\n" +
                         "    }\n" +
                         "\n" +
                         "    @Transaction\n" +
                         "    public void insertVoid(Map<String, Object> " + tInfo.clazzAlias() + ") {\n" +
                         "         ZHOpenJdbcUtil.insertVoid(tableName,removeEmpty(" + tInfo.clazzAlias() + "));\n" +
                         "    }\n" +
                         "    @Transaction\n" +
                         "    public int updateById(Map<String, Object> " + tInfo.clazzAlias() + ")  {\n" +
                         "      return  ZHOpenJdbcUtil.executeUpdate(updateAll,";
        for (ColumnInfo cInfo : tInfo.columns()) {
            service += tInfo.clazzAlias() + ".get(" + cInfo.columnName() + "),";
        }
        service += ");\n" +
                   "    }\n" +
                   "\n" +
                   "    @Transaction(readOnly = true)\n" +
                   "    public Map<String, Object> queryById(Long id) {\n" +
                   "        return  ZHOpenJdbcUtil.executeQueryOne(queryById,id);\n" +
                   "    }\n" +
                   "\n" +
                   "    @Transaction\n" +
                   "    public int deleteById(Long id)  {\n" +
                   "        return  ZHOpenJdbcUtil.executeUpdate(deleteById,id);\n" +
                   "    }\n" +
                   "\n" +
                   "}\n";
        bw.write(service);
        bw.flush();
        bw.close();
    }

    private static void createVLL(TableInfo tInfo) throws IOException {
        String dir = System.getProperty("user.dir");
        Path staticPath = Paths.get(dir, "clazz", "static.text");
        Files.createDirectories(staticPath.getParent());
        BufferedWriter staticBW = Files.newBufferedWriter(staticPath, StandardOpenOption.APPEND, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
        staticBW.write("vllBeanCache.put(" + tInfo.clazzName() + "VLL.class, new " + tInfo.clazzName() + "VLL());\n");
        staticBW.flush();
        staticBW.close();
        Path path = Paths.get(dir, "clazz/vll", tInfo.clazzName() + "VLL.java");
        Files.deleteIfExists(path);
        Files.createDirectories(path.getParent());
        BufferedWriter bw = Files.newBufferedWriter(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
        String controller = "\n" +
                            "import com.sun.net.httpserver.Headers;\n" +
                            "import com.sun.net.httpserver.HttpContext;\n" +
                            "import org.zh.sh.util.http.Controller;\n" +
                            "import org.zh.sh.util.http.HttpMethod;\n" +
                            "import org.zh.sh.util.http.RequestMapping;\n" +
                            "\n" +
                            "import java.sql.SQLException;\n" +
                            "import java.util.Map;\n" +
                            "\n" +
                            "import static org.zh.sh.config.GlobalStatic.proxy" + tInfo.clazzName() + "SV;\n" +
                            "\n" +
                            "@Controller\n" +
                            "public class  " + tInfo.clazzName() + "VLL {\n" +
                            "\n" +
                            "\n" +
                            "    @RequestMapping(value = \"/" + tInfo.clazzAlias() + "/insert\")\n" +
                            "    public Map<String, Object> insert(Map<String, Object>  " + tInfo.clazzAlias() + ") {\n" +
                            "        return proxy" + tInfo.clazzName() + "SV.insert( " + tInfo.clazzAlias() + ");\n" +
                            "    }\n" +
                            "\n" +
                            "    @RequestMapping(value = \"/" + tInfo.clazzAlias() + "/insertVoid\")\n" +
                            "    public void insertVoid(Map<String, Object>  " + tInfo.clazzAlias() + ") {\n" +
                            "        proxy" + tInfo.clazzName() + "SV.insert( " + tInfo.clazzAlias() + ");\n" +
                            "    }\n" +
                            "\n" +
                            "    @RequestMapping(value = \"/" + tInfo.clazzAlias() + "/updateById\")\n" +
                            "    public int updateById(Map<String, Object>  " + tInfo.clazzAlias() + ") {\n" +
                            "        return proxy" + tInfo.clazzName() + "SV.updateById( " + tInfo.clazzAlias() + ");\n" +
                            "    }\n" +
                            "\n" +
                            "    @RequestMapping(value = \"/" + tInfo.clazzAlias() + "/queryById\")\n" +
                            "    public Map<String, Object> queryById(Long id)  {\n" +
                            "        return proxy" + tInfo.clazzName() + "SV.queryById(id);\n" +
                            "    }\n" +
                            "\n" +
                            "    @RequestMapping(value = \"/" + tInfo.clazzAlias() + "/deleteById\")\n" +
                            "    public int deleteById(Long id) {\n" +
                            "        return proxy" + tInfo.clazzName() + "SV.deleteById(id);\n" +
                            "    }\n" +
                            "}\n";
        bw.write(controller);
        bw.flush();
        bw.close();
    }

    private static void createVLLTest(TableInfo tInfo) throws IOException {
        String dir = System.getProperty("user.dir");
        Path path = Paths.get(dir, "clazz/test", tInfo.clazzName() + "VLLTest.java");
        Files.deleteIfExists(path);
        Files.createDirectories(path.getParent());
        BufferedWriter bw = Files.newBufferedWriter(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE);

        String VLLTest = "import org.junit.jupiter.api.Test;\n" +
                         "import org.zh.sh.entity. " + tInfo.clazzName() + ";\n" +
                         "\n" +
                         "import java.net.http.HttpResponse;\n" +
                         "\n" +
                         "import static org.zh.sh.util.StaticBean.getOne" + tInfo.clazzName() + ";\n" +
                         "import static org.zh.sh.util.StaticPub.smartPost;\n" +
                         "\n" +
                         "public class  " + tInfo.clazzName() + "VLLTest {\n" +
                         "\n" +
                         "\n" +
                         "\n" +
                         "    @Test\n" +
                         "    public void queryById(){\n" +
                         "        HttpResponse<String> response = smartPost(\"/ " + tInfo.clazzAlias() + "/queryById\",4280);\n" +
                         "        System.out.println(response.statusCode());\n" +
                         "        System.out.println(response.body());\n" +
                         "    }\n" +
                         "\n" +
                         "    @Test\n" +
                         "    public void insert()  {\n" +
                         "         Map<String,Object> one = getOne" + tInfo.clazzName() + "();\n" +
                         "        HttpResponse<String> response = smartPost(\"/ " + tInfo.clazzAlias() + "/insert\", one);\n" +
                         "        System.out.println(response.statusCode());\n" +
                         "        System.out.println(response.body());\n" +
                         "    }\n" +
                         "    @Test\n" +
                         "    public void insertVoid() {\n" +
                         "         Map<String,Object> one = getOne" + tInfo.clazzName() + "();\n" +
                         "        HttpResponse<String> response = smartPost(\"/ " + tInfo.clazzAlias() + "/insertVoid\", one);\n" +
                         "        System.out.println(response.statusCode());\n" +
                         "        System.out.println(response.body());\n" +
                         "    }\n" +
                         "    @Test\n" +
                         "    public void updateById(){\n" +
                         "        Map<String,Object> one = getOne" + tInfo.clazzName() + "();\n" +
                         "        one.put(" + tInfo.clazzName() + ".Id(4280L);\n" +
                         "        HttpResponse<String> response = smartPost(\"/ " + tInfo.clazzAlias() + "/updateById\", one);\n" +
                         "        System.out.println(response.statusCode());\n" +
                         "        System.out.println(response.body());\n" +
                         "    }\n" +
                         "    @Test\n" +
                         "    public void deleteById() {\n" +
                         "        HttpResponse<String> response = smartPost(\"/ " + tInfo.clazzAlias() + "/deleteById\", 4280);\n" +
                         "        System.out.println(response.statusCode());\n" +
                         "        System.out.println(response.body());\n" +
                         "    }\n" +
                         "\n" +
                         "}";

        bw.write(VLLTest);
        bw.flush();
        bw.close();
    }

    private static void createTestBean(TableInfo tInfo) throws IOException {
        String dir = System.getProperty("user.dir");
        Path staticPath = Paths.get(dir, "clazz", "staticBean.text");
        Files.createDirectories(staticPath.getParent());
        BufferedWriter staticBW = Files.newBufferedWriter(staticPath, StandardOpenOption.APPEND, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
        Set<String> methodsName = getMethodsName();
        String staticBean = "public static  Map<String,Object>  getOne" + tInfo.clazzName() + "() {\n" +
                            "        Map<String,Object> " + tInfo.clazzAlias() + " = new  HashMap<>();\n";
        for (ColumnInfo cInfo : tInfo.columns()) {
            if (cInfo.autoincrement()) {
                continue;
            }
            String file = cInfo.beanFile();
            for (String name : methodsName) {
                if (file.endsWith(name)) {
                    staticBean += tInfo.clazzAlias() + ".put(" + tInfo.clazzName() + "." + cInfo.columnName() + ",BeanRandom." + name + "());\n";
                }
            }
        }
        staticBean += "        return  " + tInfo.clazzAlias() + ";\n" +
                      "    }\n" +
                      "\n" +
                      "    public static List<Map<String,Object>> getMore" + tInfo.clazzName() + "() {\n" +
                      "        List<Map<String,Object>>  " + tInfo.clazzAlias() + "s = new ArrayList<>();\n" +
                      "        for (int i = 0; i < 100; i++) {\n" +
                      "             " + tInfo.clazzAlias() + "s.add(getOne" + tInfo.clazzName() + "());\n" +
                      "        }\n" +
                      "        return  " + tInfo.clazzAlias() + "s;\n" +
                      "    }\n\n\n\n";
        staticBW.write(staticBean);
        staticBW.flush();
        staticBW.close();
    }

    private static Set<String> getMethodsName() {
        Set<String> methodNames = new HashSet<>();
        methodNames.add("IdentityCard");
        methodNames.add("PhoneNumber");
        methodNames.add("EthnicGroup");
        methodNames.add("Nationality");
        methodNames.add("OnboardingDate");
        methodNames.add("TeachingCertificate");
        methodNames.add("EducationalBackground");
        methodNames.add("Honnies");
        methodNames.add("Birthday");
        methodNames.add("School");
        methodNames.add("Specialty");
        methodNames.add("Gender");
        methodNames.add("Tel");
        methodNames.add("Salary");
        methodNames.add("Address");
        methodNames.add("Age");
        methodNames.add("Email");
        methodNames.add("Name");
        return methodNames;
    }
}
